home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
msdos
/
raytrace
/
pov
/
source
/
lighting.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-05
|
39KB
|
1,258 lines
/****************************************************************************
* lighting.c
*
* This module calculates lighting properties like ambient, diffuse, specular,
* reflection, refraction, etc.
*
* from Persistence of Vision Raytracer
* Copyright 1993 Persistence of Vision Team
*---------------------------------------------------------------------------
* NOTICE: This source code file is provided so that users may experiment
* with enhancements to POV-Ray and to port the software to platforms other
* than those supported by the POV-Ray Team. There are strict rules under
* which you are permitted to use this file. The rules are in the file
* named POVLEGAL.DOC which should be distributed with this file. If
* POVLEGAL.DOC is not available or for more info please contact the POV-Ray
* Team Coordinator by leaving a message in CompuServe's Graphics Developer's
* Forum. The latest version of POV-Ray may be found there as well.
*
* This program is based on the popular DKB raytracer version 2.12.
* DKBTrace was originally written by David K. Buck.
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
*
*****************************************************************************/
#include "frame.h"
#include "vector.h"
#include "povproto.h"
extern int Trace_Level;
extern FRAME Frame;
extern OBJECT *Root_Object;
extern unsigned int Options;
extern int Use_Slabs;
extern unsigned long Quality_Flags;
extern int Shadow_Test_Flag;
extern long Shadow_Ray_Tests, Shadow_Rays_Succeeded, Shadow_Cache_Hits;
extern long Reflected_Rays_Traced, Refracted_Rays_Traced;
extern long Transmitted_Rays_Traced;
extern short *hashTable;
extern unsigned short crctab[256];
#define rand3d(a,b) crctab[(int)(hashTable[(int)(hashTable[(int)((a)&0xfff)]^(b))&0xfff])&0xff]
#define COORDINATE_LIMIT 1.0e17
#define BLACK_LEVEL 0.003
/* "Small_Tolerance" is just too tight for higher order polynomial equations.
this value should probably be a variable of some sort, but for now just
use a reasonably small value. If people render real small objects real
close to each other then there may be some shading problems. Otherwise
having SHADOW_TOLERANCE as large as this won't affect images. */
#define SHADOW_TOLERANCE 1.0e-3
static void do_light PARAMS((LIGHT_SOURCE *Light_Source,
DBL *Light_Source_Depth, RAY *Light_Source_Ray, VECTOR *IPoint,
COLOUR *Light_Colour));
static int do_blocking PARAMS((INTERSECTION *Local_Intersection,
COLOUR *Light_Colour, ISTACK *Local_Stack));
static void do_phong PARAMS((FINISH *Finish, RAY *Light_Source_Ray,
VECTOR *Eye, VECTOR *Layer_Normal, COLOUR *Colour, COLOUR *Light_Colour,
COLOUR *Layer_Pigment_Colour));
static void do_specular PARAMS((FINISH *Finish, RAY *Light_Source_Ray,
VECTOR *REye, VECTOR *Layer_Normal, COLOUR *Colour, COLOUR *Light_Colour,
COLOUR *Layer_Pigment_Colour));
static void do_diffuse PARAMS((FINISH *Finish, RAY *Light_Source_Ray,
VECTOR *Layer_Normal, COLOUR *Colour, COLOUR *Light_Colour,
COLOUR *Layer_Pigment_Colour, DBL Attenuation));
static void Block_Area_Light PARAMS((LIGHT_SOURCE *Light_Source,
DBL Light_Source_Depth, RAY *Light_Source_Ray_Ptr, VECTOR *IPoint,
COLOUR *Light_Colour, int u1, int v1, int u2, int v2, int Level));
static void Block_Point_Light PARAMS((LIGHT_SOURCE *Light_Source,
DBL Light_Source_Depth, RAY *Light_Source_Ray_Ptr, COLOUR *Light_Colour));
static void Block_Point_Light (Light_Source, Light_Source_Depth, Light_Source_Ray_Ptr, Light_Colour)
LIGHT_SOURCE *Light_Source;
DBL Light_Source_Depth;
RAY *Light_Source_Ray_Ptr;
COLOUR *Light_Colour;
{
OBJECT *Blocking_Object;
int Quit_Looking, Not_Found_Shadow, Cache_Me;
INTERSECTION *Local_Intersection, Bounded_Intersection;
ISTACK *Local_Stack;
RAY Local_Ray;
RAY Light_Source_Ray;
Light_Source_Ray = *Light_Source_Ray_Ptr;
Local_Stack = open_istack ();
Quit_Looking = FALSE;
/* Test the cached object first */
/* Made changes so that semi-transparent objects never get cached */
if (Light_Source->Shadow_Cached_Object != NULL)
{
Shadow_Ray_Tests++;
if (Ray_In_Bounds (&Light_Source_Ray, Light_Source->Shadow_Cached_Object->Bound))
{
if (All_Intersections (Light_Source->Shadow_Cached_Object, &Light_Source_Ray, Local_Stack))
while ((Local_Intersection=pop_entry(Local_Stack)) != NULL)
{
if ((!Local_Intersection->Object->No_Shadow_Flag) &&
(Local_Intersection->Depth < Light_Source_Depth-Small_Tolerance) &&
(Local_Intersection->Depth > SHADOW_TOLERANCE))
if (do_blocking(Local_Intersection, Light_Colour, Local_Stack))
{
Quit_Looking = TRUE;
Shadow_Cache_Hits++;
break;
}
}
}
}
if (Quit_Looking)
{
close_istack (Local_Stack);
return;
}
Not_Found_Shadow = TRUE;
Cache_Me = FALSE;
if (!Use_Slabs)
{
for (Blocking_Object = Frame.Objects;
Blocking_Object != NULL;
Blocking_Object = Blocking_Object->Sibling)
{
if (Blocking_Object == Light_Source->Shadow_Cached_Object)
continue;
Shadow_Ray_Tests++;
if (!Ray_In_Bounds (&Light_Source_Ray, Blocking_Object->Bound))
continue;
if (!All_Intersections (Blocking_Object, &Light_Source_Ray, Local_Stack))
continue;
while ((Local_Intersection = pop_entry(Local_Stack)) != NULL)
if ((!Local_Intersection->Object->No_Shadow_Flag) &&
(Local_Intersection->Depth < Light_Source_Depth-Small_Tolerance) &&
(Local_Intersection->Depth > SHADOW_TOLERANCE))
{
if (do_blocking(Local_Intersection, Light_Colour, Local_Stack))
{
Cache_Me = Not_Found_Shadow;
Quit_Looking = TRUE;
break; /* from while */
}
Not_Found_Shadow = FALSE;
}
if (Quit_Looking)
break; /* from for */
}
}
else /* Use bounding slabs to look for shadows */
{
Local_Ray = Light_Source_Ray;
while (!Quit_Looking)
{
Shadow_Ray_Tests++;
Local_Ray.Quadric_Constants_Cached = 0;
Bounded_Intersection.Depth = Light_Source_Depth;
if (Bounds_Intersect(Root_Object, &Local_Ray, &Bounded_Intersection,
&Blocking_Object))
{
if (Bounded_Intersection.Depth > Light_Source_Depth)
break; /* Intersection was beyond the light */
if (!(Bounded_Intersection.Object->No_Shadow_Flag))
if (Blocking_Object != Light_Source->Shadow_Cached_Object)
{
Shadow_Rays_Succeeded++;
Filter_Shadow_Ray(&Bounded_Intersection, Light_Colour);
if ((fabs(Light_Colour->Red) < BLACK_LEVEL) &&
(fabs(Light_Colour->Green) < BLACK_LEVEL) &&
(fabs(Light_Colour->Blue) < BLACK_LEVEL))
{
Cache_Me = Not_Found_Shadow;
Quit_Looking = TRUE;
break; /* from while */
}
}
/* Move the ray to the point of intersection, plus some */
Light_Source_Depth -= Bounded_Intersection.Depth;
Local_Ray.Initial = Bounded_Intersection.IPoint;
Not_Found_Shadow = FALSE;
}
else /* No intersections in the direction of the ray */
{
break;
}
} /*endwhile*/
} /*endelse*/
if (Cache_Me)
Light_Source->Shadow_Cached_Object = Blocking_Object;
close_istack (Local_Stack);
}
static void Block_Area_Light (Light_Source, Light_Source_Depth,
Light_Source_Ray_Ptr,IPoint, Light_Colour, u1, v1, u2, v2, Level)
LIGHT_SOURCE *Light_Source;
DBL Light_Source_Depth;
RAY *Light_Source_Ray_Ptr;
VECTOR *IPoint;
COLOUR *Light_Colour;
int u1, v1, u2, v2, Level;
{
COLOUR Sample_Colour[4], Dummy_Colour;
VECTOR Center_Save, NewAxis1, NewAxis2;
int i, j, u, v, New_u1, New_v1, New_u2, New_v2;
DBL Jitter_u, Jitter_v, ScaleFactor;
RAY Light_Source_Ray;
Light_Source_Ray = *Light_Source_Ray_Ptr;
/* First call, initialize */
if (u1 == 0 && v1 == 0 && u2 == 0 && v2 == 0)
{
/* Flag uncalculated points with a negative value for Red */
for (i = 0; i < Light_Source->Area_Size1; i++)
{
for (j = 0; j < Light_Source->Area_Size2; j++)
Light_Source->Light_Grid[i][j].Red = -1.0;
}
u1 = 0;
v1 = 0;
u2 = Light_Source->Area_Size1 - 1;
v2 = Light_Source->Area_Size2 - 1;
}
/* Save the light source center since we'll be fiddling with it */
Center_Save=Light_Source->Center;
/* Sample the four corners of the region */
for (i = 0; i < 4; i++)
{
switch (i)
{
case 0:
u = u1; v = v1; break;
case 1:
u = u2; v = v1; break;
case 2:
u = u1; v = v2; break;
case 3:
u = u2; v = v2; break;
}
if (Light_Source -> Light_Grid[u][v].Red >= 0.0)
/* We've already calculated this point, reuse it */
Sample_Colour[i]=Light_Source->Light_Grid[u][v];
else
{
Jitter_u = (DBL)u;
Jitter_v = (DBL)v;
if (Light_Source -> Jitter)
{
Jitter_u += (rand() % 4096)/4096.0 - 0.5;
Jitter_v += (rand() % 4096)/4096.0 - 0.5;
/*
Not sure if jx = IPoint->x + 100*u;
this works jy = IPoint->y + 100*v;
yet
Jitter_u += ((rand3d(jx, jy) & 0x7FFF)/32768.0) - 0.5;
Jitter_v += ((rand3d(jx+10, jy+10) & 0x7FFF)/32768.0) - 0.5;
*/
}
if (Light_Source -> Area_Size1 > 1)
{
ScaleFactor = Jitter_u/(DBL)(Light_Source->Area_Size1 - 1) - 0.5;
VScale (NewAxis1, Light_Source->Axis1, ScaleFactor)
}
else
Make_Vector (&NewAxis1, 0.0, 0.0, 0.0);
if (Light_Source -> Area_Size2 > 1)
{
ScaleFactor = Jitter_v/(DBL)(Light_Source->Area_Size2 - 1) - 0.5;
VScale (NewAxis2, Light_Source->Axis2, ScaleFactor)
}
else
Make_Vector (&NewAxis2, 0.0, 0.0, 0.0);
Light_Source->Center=Center_Save;
VAdd (Light_Source->Center, Light_Source->Center, NewAxis1);
VAdd (Light_Source->Center, Light_Source->Center, NewAxis2);
/* Recalculate the light source ray but not the colour */
do_light (Light_Source, &Light_Source_Depth, &Light_Source_Ray,
IPoint, &Dummy_Colour);
Sample_Colour[i]= *Light_Colour;
Block_Point_Light (Light_Source, Light_Source_Depth,
&Light_Source_Ray, &Sample_Colour[i]);
Light_Source->Light_Grid[u][v]=Sample_Colour[i];
}
}
Light_Source->Center=Center_Save;
if ( (u2 - u1 > 1 || v2 - v1 > 1) && (Level < Light_Source -> Adaptive_Level ||
Colour_Distance (&Sample_Colour[0], &Sample_Colour[1]) > 0.1 ||
Colour_Distance (&Sample_Colour[1], &Sample_Colour[3]) > 0.1 ||
Colour_Distance (&Sample_Colour[3], &Sample_Colour[2]) > 0.1 ||
Colour_Distance (&Sample_Colour[2], &Sample_Colour[0]) > 0.1) )
{
for (i = 0; i < 4; i++)
{
switch (i)
{
case 0:
New_u1 = u1;
New_v1 = v1;
New_u2 = (int)floor ((u1 + u2)/2.0);
New_v2 = (int)floor ((v1 + v2)/2.0);
break;
case 1:
New_u1 = (int)ceil ((u1 + u2)/2.0);
New_v1 = v1;
New_u2 = u2;
New_v2 = (int)floor ((v1 + v2)/2.0);
break;
case 2:
New_u1 = u1;
New_v1 = (int)ceil ((v1 + v2)/2.0);
New_u2 = (int)floor ((u1 + u2)/2.0);
New_v2 = v2;
break;
case 3:
New_u1 = (int)ceil ((u1 + u2)/2.0);
New_v1 = (int)ceil ((v1 + v2)/2.0);
New_u2 = u2;
New_v2 = v2;
break;
}
/* Recalculate the light source ray but not the colour */
do_light (Light_Source, &Light_Source_Depth, &Light_Source_Ray,
IPoint, &Dummy_Colour);
Sample_Colour[i]= *Light_Colour;
Block_Area_Light (Light_Source, Light_Source_Depth,
&Light_Source_Ray, IPoint,
&Sample_Colour[i],
New_u1, New_v1, New_u2, New_v2, Level+1);
}
}
/* Add up the light contributions */
Make_Colour (Light_Colour, 0.0, 0.0, 0.0);
for (i = 0; i < 4; i++)
{
Scale_Colour (&Sample_Colour[i], &Sample_Colour[i], 0.25);
Add_Colour (Light_Colour, Light_Colour, &Sample_Colour[i]);
}
}
static void do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, IPoint, Light_Colour)
LIGHT_SOURCE *Light_Source;
DBL *Light_Source_Depth;
RAY *Light_Source_Ray;
VECTOR *IPoint;
COLOUR *Light_Colour;
{
DBL Attenuation = 1.0;
/* Get the light source colour. */
*Light_Colour = Light_Source->Colour;
Light_Source_Ray->Initial = *IPoint;
Light_Source_Ray->Quadric_Constants_Cached = FALSE;
VSub (Light_Source_Ray->Direction,
Light_Source->Center,
*IPoint);
VLength (*Light_Source_Depth, Light_Source_Ray->Direction);
VScale (Light_Source_Ray->Direction, Light_Source_Ray->Direction,
1.0/(*Light_Source_Depth));
Attenuation = Attenuate_Light(Light_Source, Light_Source_Ray);
/* Now scale the color by the attenuation */
Light_Colour->Red *= Attenuation;
Light_Colour->Green *= Attenuation;
Light_Colour->Blue *= Attenuation;
return;
}
static int do_blocking(Local_Intersection, Light_Colour, Local_Stack)
INTERSECTION *Local_Intersection;
COLOUR *Light_Colour;
ISTACK *Local_Stack;
{
Shadow_Rays_Succeeded++;
Filter_Shadow_Ray (Local_Intersection, Light_Colour);
if ((fabs(Light_Colour->Red) < BLACK_LEVEL) &&
(fabs(Light_Colour->Green) < BLACK_LEVEL) &&
(fabs(Light_Colour->Blue) < BLACK_LEVEL))
{
while ((Local_Intersection = pop_entry(Local_Stack)) != NULL)
{
}
return(TRUE);
}
return(FALSE);
}
static void do_phong(Finish, Light_Source_Ray, Eye, Layer_Normal, Colour, Light_Colour, Layer_Pigment_Colour)
FINISH *Finish;
RAY *Light_Source_Ray;
VECTOR *Layer_Normal, *Eye;
COLOUR *Colour, *Light_Colour, *Layer_Pigment_Colour;
{
DBL Cos_Angle_Of_Incidence, Normal_Length, Intensity;
VECTOR Local_Normal, Normal_Projection, Reflect_Direction;
VDot(Cos_Angle_Of_Incidence, *Eye, *Layer_Normal);
if (Cos_Angle_Of_Incidence < 0.0)
{
Local_Normal = *Layer_Normal;
Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
}
else
{
VScale (Local_Normal, *Layer_Normal, -1.0);
}
VScale (Normal_Projection, Local_Normal, Cos_Angle_Of_Incidence);
VScale (Normal_Projection, Normal_Projection, 2.0);
VAdd (Reflect_Direction, *Eye, Normal_Projection);
VDot (Cos_Angle_Of_Incidence, Reflect_Direction, Light_Source_Ray->Direction);
VLength (Normal_Length, Light_Source_Ray->Direction);
if (Normal_Length == 0.0)
Cos_Angle_Of_Incidence = 0.0;
else
Cos_Angle_Of_Incidence /= Normal_Length;
if (Cos_Angle_Of_Incidence < 0.0)
Cos_Angle_Of_Incidence = 0;
if (Finish->Phong_Size != 1.0)
Intensity = pow(Cos_Angle_Of_Incidence, Finish->Phong_Size);
else
Intensity = Cos_Angle_Of_Incidence;
Intensity *= Finish->Phong;
if (Finish->Metallic_Flag)
{
Colour->Red+=Intensity*(Layer_Pigment_Colour->Red)*(Light_Colour->Red);
Colour->Green+=Intensity*(Layer_Pigment_Colour->Green)*(Light_Colour->Green);
Colour->Blue+=Intensity*(Layer_Pigment_Colour->Blue)*(Light_Colour->Blue);
}
else
{
Colour->Red+=Intensity*(Light_Colour->Red);
Colour->Green+=Intensity*(Light_Colour->Green);
Colour->Blue+=Intensity*(Light_Colour->Blue);
}
}
static void do_specular(Finish, Light_Source_Ray, REye, Layer_Normal, Colour, Light_Colour, Layer_Pigment_Colour)
FINISH *Finish;
RAY *Light_Source_Ray;
VECTOR *Layer_Normal, *REye;
COLOUR *Colour, *Light_Colour, *Layer_Pigment_Colour;
{
DBL Cos_Angle_Of_Incidence, Normal_Length, Intensity, Halfway_Length;
VECTOR Halfway;
VHalf (Halfway, *REye, Light_Source_Ray->Direction);
VLength (Normal_Length, *Layer_Normal);
VLength (Halfway_Length, Halfway);
VDot (Cos_Angle_Of_Incidence, Halfway, *Layer_Normal);
if (Normal_Length == 0.0 || Halfway_Length == 0.0)
Cos_Angle_Of_Incidence = 0.0;
else
Cos_Angle_Of_Incidence /= (Normal_Length * Halfway_Length);
if (Cos_Angle_Of_Incidence < 0.0)
Cos_Angle_Of_Incidence = 0.0;
if (Finish->Roughness != 1.0)
Intensity = pow(Cos_Angle_Of_Incidence, Finish->Roughness);
else
Intensity = Cos_Angle_Of_Incidence;
Intensity *= Finish->Specular;
if (Finish->Metallic_Flag)
{
Colour->Red+=Intensity*(Layer_Pigment_Colour->Red)*(Light_Colour->Red);
Colour->Green+=Intensity*(Layer_Pigment_Colour->Green)*(Light_Colour->Green);
Colour->Blue+=Intensity*(Layer_Pigment_Colour->Blue)*(Light_Colour->Blue);
}
else
{
Colour->Red+=Intensity*(Light_Colour->Red);
Colour->Green+=Intensity*(Light_Colour->Green);
Colour->Blue+=Intensity*(Light_Colour->Blue);
}
}
static void do_diffuse(Finish, Light_Source_Ray, Layer_Normal, Colour, Light_Colour, Layer_Pigment_Colour, Attenuation)
FINISH *Finish;
RAY *Light_Source_Ray;
VECTOR *Layer_Normal;
COLOUR *Colour, *Light_Colour, *Layer_Pigment_Colour;
DBL Attenuation;
{
DBL Cos_Angle_Of_Incidence, Intensity;
VDot (Cos_Angle_Of_Incidence, *Layer_Normal, Light_Source_Ray->Direction);
if (Cos_Angle_Of_Incidence < 0.0)
Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
if (Finish->Brilliance != 1.0)
Intensity = pow(Cos_Angle_Of_Incidence, Finish->Brilliance);
else
Intensity = Cos_Angle_Of_Incidence;
Intensity *= Finish->Diffuse * Attenuation;
if (Finish->Crand > 0.0)
Intensity -= ((rand()&0x7FFF)/(DBL) 0x7FFF) * Finish->Crand;
Colour->Red += Intensity * (Layer_Pigment_Colour->Red) * (Light_Colour->Red);
Colour->Green += Intensity * (Layer_Pigment_Colour->Green) * (Light_Colour->Green);
Colour->Blue += Intensity * (Layer_Pigment_Colour->Blue) * (Light_Colour->Blue);
return;
}
/* Given a 3d point and a pigment, accumulate colour from that layer */
/* Formerly called "Colour_At" */
void Add_Pigment (Colour, Pigment, IPoint)
COLOUR *Colour;
PIGMENT *Pigment;
VECTOR *IPoint;
{
register DBL x, y, z;
VECTOR TPoint,PTurbulence;
if (Pigment->Trans != NULL)
MInvTransPoint (&TPoint, IPoint, Pigment->Trans);
else
TPoint = *IPoint;
x = TPoint.x;
y = TPoint.y;
z = TPoint.z;
if(Pigment->Type != WOOD_PIGMENT &&
Pigment->Type != MARBLE_PIGMENT &&
Pigment->Type != NO_PIGMENT &&
Pigment->Type != COLOUR_PIGMENT &&
/* Pigment->Type != SPOTTED_PIGMENT && */ /*maybe?*/
Pigment->Flags & HAS_TURB)
{
DTurbulence (&PTurbulence, x, y, z,
Pigment->omega,Pigment->lambda,Pigment->Octaves);
x += PTurbulence.x * Pigment->Turbulence.x;
y += PTurbulence.y * Pigment->Turbulence.y;
z += PTurbulence.z * Pigment->Turbulence.z;
}
if (x > COORDINATE_LIMIT)
x = COORDINATE_LIMIT;
else
if (x < -COORDINATE_LIMIT)
x = -COORDINATE_LIMIT;
if (y > COORDINATE_LIMIT)
y = COORDINATE_LIMIT;
else
if (y < -COORDINATE_LIMIT)
y = -COORDINATE_LIMIT;
if (z > COORDINATE_LIMIT)
z = COORDINATE_LIMIT;
else
if (z < -COORDINATE_LIMIT)
z = -COORDINATE_LIMIT;
switch (Pigment->Type)
{
case NO_PIGMENT:
/* No colouring pigment has been specified - make it black. */
Make_Colour (Colour, 0.0, 0.0, 0.0);
Colour -> Filter = 0.0;
break;
case COLOUR_PIGMENT:
Colour -> Red += Pigment->Colour1->Red;
Colour -> Green += Pigment->Colour1->Green;
Colour -> Blue += Pigment->Colour1->Blue;
Colour -> Filter += Pigment->Colour1->Filter;
break;
case BOZO_PIGMENT:
bozo (x, y, z, Pigment, Colour);
break;
case MARBLE_PIGMENT:
marble (x, y, z, Pigment, Colour);
break;
case WOOD_PIGMENT:
wood (x, y, z, Pigment, Colour);
break;
case CHECKER_PIGMENT:
checker (x, y, z, Pigment, Colour);
break;
case SPOTTED_PIGMENT:
spotted (x, y, z, Pigment, Colour);
break;
case AGATE_PIGMENT:
agate (x, y, z, Pigment, Colour);
break;
case GRANITE_PIGMENT:
granite (x, y, z, Pigment, Colour);
break;
case GRADIENT_PIGMENT:
gradient (x, y, z, Pigment, Colour);
break;
case HEXAGON_PIGMENT:
hexagon (x, y, z, Pigment, Colour);
break;
case RADIAL_PIGMENT:
radial (x, y, z, Pigment, Colour);
break;
case MANDEL_PIGMENT:
mandel (x, y, z, Pigment, Colour);
break;
case IMAGE_MAP_PIGMENT:
image_map (x, y, z, Pigment, Colour);
break;
case ONION_PIGMENT:
onion (x, y, z, Pigment, Colour);
break;
case LEOPARD_PIGMENT:
leopard (x, y, z, Pigment, Colour);
break;
case PAINTED1_PIGMENT:
painted1 (x, y, z, Pigment, Colour);
break;
case PAINTED2_PIGMENT:
painted2 (x, y, z, Pigment, Colour);
break;
case PAINTED3_PIGMENT:
painted3 (x, y, z, Pigment, Colour);
break;
}
}
void Perturb_Normal(Layer_Normal, Tnormal, IPoint)
VECTOR *Layer_Normal, *IPoint;
TNORMAL *Tnormal;
{
register DBL x, y, z;
VECTOR TPoint,NTurbulence;
if (Tnormal->Trans != NULL)
MInvTransPoint (&TPoint, IPoint, Tnormal->Trans);
else
TPoint = *IPoint;
x = TPoint.x;
y = TPoint.y;
z = TPoint.z;
if(Tnormal->Flags & HAS_TURB)
{
DTurbulence (&NTurbulence, x, y, z,
Tnormal->omega,Tnormal->lambda,Tnormal->Octaves);
x += NTurbulence.x * Tnormal->Turbulence.x;
y += NTurbulence.y * Tnormal->Turbulence.y;
z += NTurbulence.z * Tnormal->Turbulence.z;
}
switch (Tnormal->Type)
{
case WAVES:
waves (x, y, z, Tnormal, Layer_Normal);
break;
case RIPPLES:
ripples (x, y, z, Tnormal, Layer_Normal);
break;
case WRINKLES:
wrinkles (x, y, z, Tnormal, Layer_Normal);
break;
case BUMPS:
bumps (x, y, z, Tnormal, Layer_Normal);
break;
case DENTS:
dents (x, y, z, Tnormal, Layer_Normal);
break;
case BUMPY1:
bumpy1 (x, y, z, Tnormal, Layer_Normal);
break;
case BUMPY2:
bumpy2 (x, y, z, Tnormal, Layer_Normal);
break;
case BUMPY3:
bumpy3 (x, y, z, Tnormal, Layer_Normal);
break;
case BUMP_MAP:
bump_map (x, y, z, Tnormal, Layer_Normal);
break;
}
return;
}
void Diffuse (Finish, IPoint, Eye, Layer_Normal, Layer_Pigment_Colour, Colour, Attenuation, Object)
FINISH *Finish;
VECTOR *IPoint, *Layer_Normal;
COLOUR *Layer_Pigment_Colour;
COLOUR *Colour;
RAY *Eye;
DBL Attenuation;
OBJECT *Object;
{
DBL Light_Source_Depth, Cos_Shadow_Angle;
RAY Light_Source_Ray;
LIGHT_SOURCE *Light_Source;
VECTOR REye;
COLOUR Light_Colour;
if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0))
return;
if (Finish->Specular != 0.0)
{
REye.x = -Eye->Direction.x;
REye.y = -Eye->Direction.y;
REye.z = -Eye->Direction.z;
}
for (Light_Source = Frame.Light_Sources ;
Light_Source != NULL;
Light_Source = Light_Source->Next_Light_Source)
{
/* Get a colour and a ray */
do_light(Light_Source, &Light_Source_Depth,
&Light_Source_Ray, IPoint,
&Light_Colour);
/* Don't calculate spotlights when outside of the light's cone */
if (fabs(Light_Colour.Red) < BLACK_LEVEL &&
fabs(Light_Colour.Green) < BLACK_LEVEL &&
fabs(Light_Colour.Blue) < BLACK_LEVEL)
continue;
/* See if light on far side of surface from camera. */
if (!(Object->Type & DOUBLE_ILLUMINATE))
{
VDot(Cos_Shadow_Angle,*Layer_Normal,Light_Source_Ray.Direction);
if (Cos_Shadow_Angle < 0.0)
continue;
}
/* If light source was not blocked by any intervening object, then
calculate it's contribution to the object's overall illumination */
Shadow_Test_Flag = TRUE;
if (Quality_Flags & Q_SHADOW)
{
if ((Light_Source->Area_Light) && (Quality_Flags & Q_AREA_LIGHT))
Block_Area_Light (Light_Source, Light_Source_Depth,
&Light_Source_Ray, IPoint,
&Light_Colour, 0, 0, 0, 0, 0);
else
Block_Point_Light (Light_Source, Light_Source_Depth,
&Light_Source_Ray, &Light_Colour);
}
Shadow_Test_Flag = FALSE;
if (fabs(Light_Colour.Red) > BLACK_LEVEL ||
fabs(Light_Colour.Green) > BLACK_LEVEL ||
fabs(Light_Colour.Blue) > BLACK_LEVEL)
{
if (Finish->Phong > 0.0)
do_phong(Finish,&Light_Source_Ray,&Eye->Direction,Layer_Normal,Colour,&Light_Colour, Layer_Pigment_Colour);
if (Finish->Specular > 0.0)
do_specular(Finish,&Light_Source_Ray,&REye,Layer_Normal,Colour,&Light_Colour, Layer_Pigment_Colour);
if (Finish->Diffuse > 0.0)
do_diffuse(Finish,&Light_Source_Ray,Layer_Normal,Colour,&Light_Colour,Layer_Pigment_Colour, Attenuation);
}
}
return;
}
void Reflect (Reflection, IPoint, Ray, Layer_Normal, Colour)
DBL Reflection;
VECTOR *IPoint;
RAY *Ray;
VECTOR *Layer_Normal;
COLOUR *Colour;
{
RAY New_Ray;
COLOUR Temp_Colour;
VECTOR Local_Normal;
VECTOR Normal_Projection;
VECTOR Surface_Offset;
register DBL Normal_Component;
if (Reflection != 0.0)
{
Reflected_Rays_Traced++;
VDot (Normal_Component, Ray -> Direction, *Layer_Normal);
if (Normal_Component < 0.0)
{
Local_Normal = *Layer_Normal;
Normal_Component *= -1.0;
}
else
VScale (Local_Normal, *Layer_Normal, -1.0);
VScale (Normal_Projection, Local_Normal, Normal_Component);
VScale (Normal_Projection, Normal_Projection, 2.0);
VAdd (New_Ray.Direction, Ray -> Direction, Normal_Projection);
New_Ray.Initial = *IPoint;
/* ARE 08/25/91 */
VScale(Surface_Offset, New_Ray.Direction, 2.0 * Small_Tolerance);
VAdd(New_Ray.Initial, New_Ray.Initial, Surface_Offset);
Copy_Ray_Containers (&New_Ray, Ray);
Trace_Level++;
Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
New_Ray.Quadric_Constants_Cached = FALSE;
Trace (&New_Ray, &Temp_Colour);
Trace_Level--;
Colour -> Red += Temp_Colour.Red * Reflection;
Colour -> Green += Temp_Colour.Green * Reflection;
Colour -> Blue += Temp_Colour.Blue * Reflection;
}
}
void Refract (Texture, IPoint, Ray, Top_Normal, Colour)
TEXTURE *Texture;
VECTOR *IPoint;
RAY *Ray;
VECTOR *Top_Normal;
COLOUR *Colour;
{
RAY New_Ray;
COLOUR Temp_Colour;
VECTOR Local_Normal;
VECTOR Ray_Direction;
register DBL Normal_Component, Temp_IOR;
DBL temp, ior;
/* int inside; */
if (Top_Normal == NULL)
{
New_Ray.Initial = *IPoint;
New_Ray.Direction = Ray->Direction;
Copy_Ray_Containers (&New_Ray, Ray);
Trace_Level++;
Transmitted_Rays_Traced++;
Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
New_Ray.Quadric_Constants_Cached = FALSE;
Trace (&New_Ray, &Temp_Colour);
Trace_Level--;
(Colour -> Red) += Temp_Colour.Red;
(Colour -> Green) += Temp_Colour.Green;
(Colour -> Blue) += Temp_Colour.Blue;
}
else
{
Refracted_Rays_Traced++;
VDot (Normal_Component, Ray -> Direction, *Top_Normal);
if (Normal_Component <= 0.0)
{
Local_Normal.x = Top_Normal -> x;
Local_Normal.y = Top_Normal -> y;
Local_Normal.z = Top_Normal -> z;
Normal_Component *= -1.0;
/* inside = FALSE;*/
}
else
{
VScale (Local_Normal, *Top_Normal, -1.0);
/* inside = TRUE;*/
}
Copy_Ray_Containers (&New_Ray, Ray);
if (Ray -> Containing_Index == -1)
{
/* The ray is entering from the atmosphere */
Ray_Enter (&New_Ray, Texture);
ior = (Frame.Atmosphere_IOR)/(Texture->Finish->Index_Of_Refraction);
}
else
{
/* The ray is currently inside an object */
if (New_Ray.Containing_Textures [New_Ray.Containing_Index] == Texture)
/* if (inside) */
{
/* The ray is leaving the current object */
Ray_Exit (&New_Ray);
if (New_Ray.Containing_Index == -1)
/* The ray is leaving into the atmosphere */
Temp_IOR = Frame.Atmosphere_IOR;
else
/* The ray is leaving into another object */
Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
ior = (Texture->Finish->Index_Of_Refraction)/Temp_IOR;
}
else
{
/* The ray is entering a new object */
Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
Ray_Enter (&New_Ray, Texture);
ior = Temp_IOR / (Texture->Finish->Index_Of_Refraction);
}
}
temp = 1.0 + ior * ior * (Normal_Component * Normal_Component - 1.0);
if (temp < 0.0)
{
Reflect ((1.0 - Texture->Finish->Reflection), IPoint,
Ray, Top_Normal, Colour);
return;
}
temp = ior*Normal_Component - sqrt(temp);
VScale (Local_Normal, Local_Normal, temp);
VScale (Ray_Direction, Ray->Direction, ior);
VAdd (New_Ray.Direction, Local_Normal, Ray_Direction);
VNormalize (New_Ray.Direction, New_Ray.Direction);
New_Ray.Initial = *IPoint;
Trace_Level++;
Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
New_Ray.Quadric_Constants_Cached = FALSE;
Trace (&New_Ray, &Temp_Colour);
Trace_Level--;
(Colour -> Red) += (Temp_Colour.Red)
* (Texture -> Finish->Refraction);
(Colour -> Green) += (Temp_Colour.Green)
* (Texture -> Finish->Refraction);
(Colour -> Blue) += (Temp_Colour.Blue)
* (Texture -> Finish->Refraction);
}
}
void Fog (Distance, Fog_Colour, Fog_Distance, Colour)
DBL Distance, Fog_Distance;
COLOUR *Fog_Colour, *Colour;
{
DBL Fog_Factor, Fog_Factor_Inverse;
Fog_Factor = exp(-1.0 * Distance/Fog_Distance);
Fog_Factor_Inverse = 1.0 - Fog_Factor;
Colour->Red = Colour->Red*Fog_Factor + Fog_Colour->Red*Fog_Factor_Inverse;
Colour->Green = Colour->Green*Fog_Factor + Fog_Colour->Green*Fog_Factor_Inverse;
Colour->Blue = Colour->Blue*Fog_Factor + Fog_Colour->Blue*Fog_Factor_Inverse;
}
void Compute_Reflected_Colour (Ray, Finish, Ray_Intersection, Layer_Pigment_Colour, Filter_Colour, Colour, Layer_Normal)
RAY *Ray;
FINISH *Finish;
INTERSECTION *Ray_Intersection;
COLOUR *Layer_Pigment_Colour;
COLOUR *Filter_Colour;
COLOUR *Colour;
VECTOR *Layer_Normal;
{
DBL Attenuation, Ambient;
COLOUR Emitted_Colour;
/* This variable keeps track of how much colour comes from the surface
of the object and how much is transmited through. */
Make_Colour (&Emitted_Colour, 0.0, 0.0, 0.0);
if (Quality_Flags & Q_FULL_AMBIENT)
{
Layer_Pigment_Colour->Filter = 0.0;
Colour->Red += Layer_Pigment_Colour->Red * Filter_Colour->Filter;
Colour->Green += Layer_Pigment_Colour->Green * Filter_Colour->Filter;
Colour->Blue += Layer_Pigment_Colour->Blue * Filter_Colour->Filter;
return;
}
Attenuation = Filter_Colour->Filter * (1.0 - Layer_Pigment_Colour->Filter);
if ((Ambient = Finish->Ambient*Attenuation) != 0.0)
{
Emitted_Colour.Red += Layer_Pigment_Colour->Red * Ambient;
Emitted_Colour.Green += Layer_Pigment_Colour->Green * Ambient;
Emitted_Colour.Blue += Layer_Pigment_Colour->Blue * Ambient;
}
Diffuse (Finish, &Ray_Intersection->IPoint, Ray,
Layer_Normal, Layer_Pigment_Colour, &Emitted_Colour, Attenuation,
Ray_Intersection->Object);
Colour->Red += Emitted_Colour.Red;
Colour->Green += Emitted_Colour.Green;
Colour->Blue += Emitted_Colour.Blue;
if (Quality_Flags & Q_REFLECT)
Reflect (Finish->Reflection, &Ray_Intersection -> IPoint, Ray,
Layer_Normal, Colour);
}
/* Given an intersection point, a ray, & a shadow flag, add that point's
color to the given colour and return it. */
void Determine_Apparent_Colour (Ray_Intersection, Colour, Ray)
INTERSECTION *Ray_Intersection;
COLOUR *Colour;
RAY *Ray;
{
COLOUR Layer_Pigment_Colour, Refracted_Colour, Filter_Colour;
TEXTURE *Layer, *Texture;
FINISH *Finish;
VECTOR Layer_Normal, Raw_Normal, Top_Normal;
DBL Normal_Direction;
int layer_number;
#define QColour Texture->Pigment->Quick_Colour
/* Get the normal to the surface */
if (Ray_Intersection->NFlag)
Raw_Normal = Ray_Intersection->INormal;
else
Normal (&Raw_Normal, Ray_Intersection->Object, &Ray_Intersection->IPoint);
/* Now, we perform the lighting calculations. */
/* We assume here that Post_Process has propagated all parent
textures to the object itself and that everything has some texture.
Redirrect to the proper texture if its a material or checker texture */
for (Texture = Ray_Intersection->Object->Texture;
Texture->Type != PNF_TEXTURE;)
switch (Texture->Type)
{
case TILE_TEXTURE:
Texture = tiles_texture(&Ray_Intersection->IPoint,((TILES *)Texture));
break;
case MAT_TEXTURE:
Texture = material_map(&Ray_Intersection->IPoint,((MATERIAL *)Texture));
break;
default:
fprintf(stderr, "Bad texture type: %d\n", Texture->Type);
close_all();
exit(1);
};
Make_ColourA (&Filter_Colour, 1.0, 1.0, 1.0, 1.0);
for (layer_number=1 , Layer = Texture;
(Layer != NULL) && (fabs(Filter_Colour.Filter) > BLACK_LEVEL);
layer_number++, Layer = Layer->Next_Layer)
{
Make_Colour (&Layer_Pigment_Colour, 0.0, 0.0, 0.0);
if (Quality_Flags & Q_QUICKC)
Layer_Pigment_Colour = QColour;
else
Add_Pigment (&Layer_Pigment_Colour, Layer->Pigment, &Ray_Intersection->IPoint);
Layer_Normal = Raw_Normal;
if ((Quality_Flags & Q_NORMAL) && (Texture->Tnormal != NULL))
Perturb_Normal (&Layer_Normal, Texture->Tnormal,
&Ray_Intersection->IPoint);
/* If the surface normal points away, flip its direction. */
VDot (Normal_Direction, Layer_Normal, Ray->Direction);
if (Normal_Direction > 0.0)
{
VScaleEq (Layer_Normal, -1.0);
}
if (layer_number == 1)
Top_Normal = Layer_Normal;
Compute_Reflected_Colour (Ray,
Layer->Finish,
Ray_Intersection,
&Layer_Pigment_Colour,
&Filter_Colour,
Colour, &Layer_Normal);
Filter_Colour.Red *= Layer_Pigment_Colour.Red;
Filter_Colour.Green *= Layer_Pigment_Colour.Green;
Filter_Colour.Blue *= Layer_Pigment_Colour.Blue;
Filter_Colour.Filter *= Layer_Pigment_Colour.Filter;
}
Finish = Texture->Finish;
if ((fabs(Filter_Colour.Filter) > BLACK_LEVEL) && (Quality_Flags & Q_REFRACT))
{
Make_Colour (&Refracted_Colour, 0.0, 0.0, 0.0);
if (Finish->Refraction > 0.0)
Refract (Texture, &Ray_Intersection -> IPoint, Ray,
&Top_Normal, &Refracted_Colour);
else
Refract (Texture, &Ray_Intersection->IPoint, Ray,
NULL, &Refracted_Colour);
Colour->Red += Filter_Colour.Red * Refracted_Colour.Red * Filter_Colour.Filter;
Colour->Green += Filter_Colour.Green * Refracted_Colour.Green * Filter_Colour.Filter;
Colour->Blue += Filter_Colour.Blue * Refracted_Colour.Blue * Filter_Colour.Filter;
}
if (Frame.Fog_Distance != 0.0)
Fog (Ray_Intersection->Depth, &Frame.Fog_Colour, Frame.Fog_Distance,
Colour);
}
void Filter_Shadow_Ray (Ray_Intersection, Colour)
INTERSECTION *Ray_Intersection;
COLOUR *Colour;
{
COLOUR Layer_Pigment_Colour, Filter_Colour;
TEXTURE *Layer, *Texture;
FINISH *Finish;
int layer_number;
#define QColour Texture->Pigment->Quick_Colour
if (!(Quality_Flags & Q_SHADOW))
return;
/* Now, we perform the lighting calculations. */
/* We assume here that Post_Process has propagated all parent
textures to the object itself and that everything has some texture.
Redirrect to the proper texture if its a material or checker texture */
for (Texture = Ray_Intersection->Object->Texture;
Texture->Type != PNF_TEXTURE;)
switch (Texture->Type)
{
case TILE_TEXTURE:
Texture = tiles_texture(&Ray_Intersection->IPoint,((TILES *)Texture));
break;
case MAT_TEXTURE:
Texture = material_map(&Ray_Intersection->IPoint,((MATERIAL *)Texture));
break;
default:
fprintf(stderr, "Bad texture type: %d\n", Texture->Type);
close_all();
exit(1);
};
Make_ColourA (&Filter_Colour, 1.0, 1.0, 1.0, 1.0);
for (layer_number=1 , Layer = Texture;
(Layer != NULL) && (fabs(Filter_Colour.Filter) > BLACK_LEVEL);
layer_number++, Layer = Layer->Next_Layer)
{
if (Quality_Flags & Q_QUICKC)
Layer_Pigment_Colour = QColour;
else
{
Make_Colour (&Layer_Pigment_Colour, 0.0, 0.0, 0.0);
Add_Pigment (&Layer_Pigment_Colour, Layer->Pigment, &Ray_Intersection->IPoint);
}
Filter_Colour.Red *= Layer_Pigment_Colour.Red;
Filter_Colour.Green *= Layer_Pigment_Colour.Green;
Filter_Colour.Blue *= Layer_Pigment_Colour.Blue;
Filter_Colour.Filter *= Layer_Pigment_Colour.Filter;
}
Finish = Texture->Finish;
/* For shadow rays, we have the filter colour now - time to return */
if (fabs(Filter_Colour.Filter) < BLACK_LEVEL)
{
Make_Colour (Colour, 0.0, 0.0, 0.0);
return;
}
if (Finish->Refraction > 0.0)
{
Colour->Red *= Filter_Colour.Red * Finish->Refraction * Filter_Colour.Filter;
Colour->Green *= Filter_Colour.Green * Finish->Refraction * Filter_Colour.Filter;
Colour->Blue *= Filter_Colour.Blue * Finish->Refraction * Filter_Colour.Filter;
}
else
{
Colour->Red *= Filter_Colour.Red * Filter_Colour.Filter;
Colour->Green *= Filter_Colour.Green * Filter_Colour.Filter;
Colour->Blue *= Filter_Colour.Blue * Filter_Colour.Filter;
}
return;
}